* entry
* ├── image.left
* ├── image.right
+ * ├── undershoot.left
+ * ├── undershoot.right
* ├── [selection]
* ├── [progress[.pulse]]
* ╰── [window.popup]
*
* The CSS node for a context menu is added as a subnode below entry as well.
*
+ * The undrshoot nodes are used to draw the underflow indication when content
+ * is scrolled out of view. These nodes get the .left and .right style classes
+ * added depending on where the indication is drawn.
+ *
* When touch is used and touch selection handles are shown, they are using
* CSS nodes with name cursor-handle. They get the .top or .bottom style class
* depending on where they are shown in relation to the selection. If there is
GtkCssGadget *gadget;
GtkCssNode *selection_node;
GtkCssNode *progress_node;
+ GtkCssNode *undershoot_node[2];
gfloat xalign;
static void gtk_entry_move_adjustments (GtkEntry *entry);
static void gtk_entry_update_cached_style_values(GtkEntry *entry);
static gboolean get_middle_click_paste (GtkEntry *entry);
+static void gtk_entry_get_scroll_limits (GtkEntry *entry,
+ gint *min_offset,
+ gint *max_offset);
/* GtkTextHandle handlers */
static void gtk_entry_handle_drag_started (GtkTextHandle *handle,
{
GtkEntryPrivate *priv;
GtkCssNode *widget_node;
+ gint i;
entry->priv = gtk_entry_get_instance_private (entry);
priv = entry->priv;
gtk_entry_render,
NULL,
NULL);
+
+ for (i = 0; i < 2; i++)
+ {
+ priv->undershoot_node[i] = gtk_css_node_new ();
+ gtk_css_node_set_name (priv->undershoot_node[i], I_("undershoot"));
+ gtk_css_node_add_class (priv->undershoot_node[i], g_quark_from_static_string (i == 0 ? GTK_STYLE_CLASS_LEFT : GTK_STYLE_CLASS_RIGHT));
+ gtk_css_node_set_parent (priv->undershoot_node[i], widget_node);
+ gtk_css_node_set_state (priv->undershoot_node[i], gtk_css_node_get_state (widget_node));
+ g_object_unref (priv->undershoot_node[i]);
+ }
}
static void
return GDK_EVENT_PROPAGATE;
}
+#define UNDERSHOOT_SIZE 20
+
+static void
+gtk_entry_draw_undershoot (GtkEntry *entry,
+ cairo_t *cr)
+{
+ GtkEntryPrivate *priv = entry->priv;
+ GtkStyleContext *context;
+ gint min_offset, max_offset;
+ GtkAllocation allocation;
+ GdkRectangle rect;
+
+ context = gtk_widget_get_style_context (GTK_WIDGET (entry));
+
+ gtk_entry_get_scroll_limits (entry, &min_offset, &max_offset);
+
+ gtk_css_gadget_get_content_allocation (priv->gadget, &rect, NULL);
+ gtk_widget_get_allocation (GTK_WIDGET (entry), &allocation);
+ rect.x -= allocation.x;
+ rect.y -= allocation.y;
+
+ if (priv->scroll_offset > min_offset)
+ {
+ gtk_style_context_save_to_node (context, priv->undershoot_node[0]);
+ gtk_render_background (context, cr, rect.x, rect.y, UNDERSHOOT_SIZE, rect.height);
+ gtk_render_frame (context, cr, rect.x, rect.y, UNDERSHOOT_SIZE, rect.height);
+ gtk_style_context_restore (context);
+ }
+
+ if (priv->scroll_offset < max_offset)
+ {
+ gtk_style_context_save_to_node (context, priv->undershoot_node[1]);
+ gtk_render_background (context, cr, rect.x + rect.width - UNDERSHOOT_SIZE, rect.y, UNDERSHOOT_SIZE, rect.height);
+ gtk_render_frame (context, cr, rect.x + rect.width - UNDERSHOOT_SIZE, rect.y, UNDERSHOOT_SIZE, rect.height);
+ gtk_style_context_restore (context);
+ }
+}
+
static gboolean
gtk_entry_render (GtkCssGadget *gadget,
cairo_t *cr,
if (icon_info != NULL)
gtk_css_gadget_draw (icon_info->gadget, cr);
}
+
+ gtk_entry_draw_undershoot (entry, cr);
}
return FALSE;
}
static void
-gtk_entry_adjust_scroll (GtkEntry *entry)
+gtk_entry_get_scroll_limits (GtkEntry *entry,
+ gint *min_offset,
+ gint *max_offset)
{
GtkEntryPrivate *priv = entry->priv;
- gint min_offset, max_offset;
- gint text_width;
- gint strong_x, weak_x;
- gint strong_xoffset, weak_xoffset;
gfloat xalign;
PangoLayout *layout;
PangoLayoutLine *line;
PangoRectangle logical_rect;
- GtkTextHandleMode handle_mode;
-
- if (!gtk_widget_get_realized (GTK_WIDGET (entry)))
- return;
+ gint text_width;
layout = gtk_entry_ensure_layout (entry, TRUE);
line = pango_layout_get_lines_readonly (layout)->data;
if (text_width > priv->text_allocation.width)
{
- min_offset = 0;
- max_offset = text_width - priv->text_allocation.width;
+ *min_offset = 0;
+ *max_offset = text_width - priv->text_allocation.width;
}
else
{
- min_offset = (text_width - priv->text_allocation.width) * xalign;
- max_offset = min_offset;
+ *min_offset = (text_width - priv->text_allocation.width) * xalign;
+ *max_offset = *min_offset;
}
+}
+
+static void
+gtk_entry_adjust_scroll (GtkEntry *entry)
+{
+ GtkEntryPrivate *priv = entry->priv;
+ gint min_offset, max_offset;
+ gint strong_x, weak_x;
+ gint strong_xoffset, weak_xoffset;
+ GtkTextHandleMode handle_mode;
+
+ if (!gtk_widget_get_realized (GTK_WIDGET (entry)))
+ return;
+
+ gtk_entry_get_scroll_limits (entry, &min_offset, &max_offset);
priv->scroll_offset = CLAMP (priv->scroll_offset, min_offset, max_offset);